const fs = require('fs')
const path = require('path')
// 语法解析模块
const parser = require('@babel/parser')
// 根据节点树 分析对应的依赖项
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')

// 模块分析
const moduleAnalyser = (filename) => {
  const content = fs.readFileSync(filename, 'utf-8')
  // console.log(content)
  // 使用babel 处理ES6语法 解析为节点树
  const ast = parser.parse(content, {
    sourceType: 'module'
  })
  // 保存依赖
  const dependencies = {}
  // 分析依赖
  traverse(ast, {
    ImportDeclaration({ node }) {
      // 处理路径
      const dirname = path.dirname(filename)
      // console.log(dirname)
      const newFile = path.join(dirname, node.source.value)
      // dependencies.push(newFile)
      dependencies[node.source.value] = newFile
    }
  })
  // console.log(dependencies)
  // 使用babel转换 转换为浏览器可以运行的代码
  const { code } = babel.transformFromAst(ast, null, {
    // 如果报错使用 以下两个中的一个
    // presets: ['@babel/preset-env']
    presets: ['@babel/env']
  })
  return {
    filename,
    dependencies,
    code
  }
}
const makeDependenciesGraph = (entry) => {
  const entryModule = moduleAnalyser(entry)
  const graphArray = [entryModule]
  // 循环取依赖
  for (let i = 0; i < graphArray.length; i++) {
    const item = graphArray[i]
    const { dependencies } = item
    if (dependencies) {
      for (let j in dependencies) {
        graphArray.push(
          moduleAnalyser(dependencies[j])
        )
      }
    }
  }
  // 将依赖放入对象
  const graph = {}
  graphArray.forEach(item => {
    graph[item.filename] = {
      dependencies: item.dependencies,
      code: item.code
    }
  })
  return graph
}
// 生成代码
const generateCode = (entry) => {
  const graph = JSON.stringify(makeDependenciesGraph(entry))
  return `
  (
    function (graph) {
      function require(module) {
        function localRequire(relativePath) {
          return require(graph[module].dependencies[relativePath])
        }
        var exports = {};
        (function (require, exports, code) {
          eval(code)
        })(localRequire,exports,graph[module].code)
        return exports
      }
      require('${entry}')
    }
  )(${graph})
  `
}

const graphInfo = generateCode('./src/index.js')
console.log(graphInfo)


